package com.gpframework.module.order.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.extra.qrcode.QrCodeUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Maps;
import com.gpframework.common.config.GpframeworkConfig;
import com.gpframework.common.constant.Constants;
import com.gpframework.common.constant.HttpStatus;
import com.gpframework.common.core.domain.AjaxResult;
import com.gpframework.common.enums.FormTypeEnum;
import com.gpframework.common.enums.OrderCharacteristicsEnum;
import com.gpframework.common.enums.OrderStatusEnum;
import com.gpframework.common.enums.YesNoEnum;
import com.gpframework.common.utils.DateUtils;
import com.gpframework.common.utils.StringUtils;
import com.gpframework.common.utils.uuid.IdGenUtils;
import com.gpframework.common.utils.uuid.IdUtils;
import com.gpframework.module.order.domain.GpFlowConfig;
import com.gpframework.module.order.domain.GpOrder;
import com.gpframework.module.order.domain.GpProduct;
import com.gpframework.module.order.domain.GpProductDetails;
import com.gpframework.module.order.domain.req.*;
import com.gpframework.module.order.domain.vo.GpHomeStatisticsVo;
import com.gpframework.module.order.domain.vo.GpOrderVo;
import com.gpframework.module.order.mapper.GpOrderMapper;
import com.gpframework.module.order.service.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

/**
 * @ClassName GpOrder
 * @Author gpframework
 * @Date 2023-06-16
 * @Version 1.0.0
 * @Description 销售单Service业务层处理
 */
@Service
public class GpOrderServiceImpl extends ServiceImpl<GpOrderMapper, GpOrder> implements IGpOrderService {

    //凭证有效时间
    private static final String KEY_EXPIRES_IN = "expiresIn";
    //
    private static final String KEY_TOKEN = "accessToken";
    //拼接缓存前缀
    private static final String ACCESS_TOKEN_KEY_PREFIX = "AccessToken_";
    /**
     * accessToken缓存
     */
    private static Map<String, Map<String, Object>> accessTokenMap = Maps.newConcurrentMap();

    @Autowired
    private IGpProductService gpProductService;
    @Autowired
    private IGpProductDetailsService gpProductDetailsService;
    @Autowired
    private IGpFlowConfigService gpFlowConfigService;
    @Autowired
    private IGpOrderNotifyService gpOrderNotifyService;

    /**
     * @Description 查询列表返回VO 用于返回给前端的列表接口
     * @Author gpframework
     * @Date 2023-06-16
     * @Param [lqw]
     * @Return List<GpOrderVo>
     */
    @Override
    public List<GpOrderVo> listVo(QueryWrapper<GpOrder> lqw) {
        List<GpOrderVo> gpOrderVos = this.baseMapper.listVo(lqw);
        for (GpOrderVo gpOrderVo : gpOrderVos) {
            gpOrderVo.setSubOrderId(this.baseMapper.getSubOrderId(gpOrderVo.getId()));
        }
        return gpOrderVos;
    }

    /**
     * @Description 查询列表返回VO 用于返回给前端的列表接口
     * @Author gpframework
     * @Date 2023-06-16
     * @Param [lqw]
     * @Return List<GpOrderVo>
     */
    @Override
    public List<GpOrderVo> listVo(GpOrderReq gpOrderReq) {
        List<GpOrderVo> gpOrderVos = this.baseMapper.queryList(gpOrderReq);
        for (GpOrderVo gpOrderVo : gpOrderVos) {
            gpOrderVo.setSubOrderId(this.baseMapper.getSubOrderId(gpOrderVo.getId()));
        }
        return gpOrderVos;
    }

    @Override
    public List<GpOrderVo> listVoHistory(QueryWrapper<GpOrder> lqw) {
        List<GpOrderVo> gpOrderVos = this.baseMapper.listVoHistory(lqw);
        for (GpOrderVo gpOrderVo : gpOrderVos) {
            gpOrderVo.setSubOrderId(this.baseMapper.getSubOrderHistoryId(gpOrderVo.getId()));
        }
        return gpOrderVos;
    }

    /**
     * @Description 通过查询详情VO 用于返回给前端的列详情接口
     * @Author gpframework
     * @Date 2023-06-16
     * @Param [id]
     * @Return GpOrderVo
     */
    @Override
    public GpOrderVo getVoById(Long id) {
        return this.baseMapper.getVo(id);
    }

    @Override
    @Transactional
    public AjaxResult collection(GpOrderAdd orderAdd) {
        // 保存订单信息
        GpOrder gpOrder = Convert.convert(new TypeReference<GpOrder>() {}, orderAdd);
        GpOrder order = this.getOne(new QueryWrapper<GpOrder>().eq("order_cloud_number", gpOrder.getOrderCloudNumber()).eq("del_status", YesNoEnum.NO.getKey()));
        if (order != null) {
            return AjaxResult.error(HttpStatus.CONFLICT,"【" + order.getCreateBy() + "】" + DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", order.getCreateTime()) + "已录入，请勿重复录入");
        }
        // 初始化订单状态
        if (StringUtils.isBlank(gpOrder.getOrderCloudNumber())) {
            gpOrder.setOrderCloudNumber(IdGenUtils.getSnowIdStr());
        }
        gpOrder.setOrderStatus(OrderStatusEnum.TO_BE_PICKING_UP_GOODS.getKey());
        this.save(gpOrder);
        // 保存订单产品信息
        GpProduct gpProduct;
        GpProductDetails gpProductDetails;
        Long orderId = gpOrder.getId();
        Long productId;
        BigDecimal workload = BigDecimal.ZERO;
        String orderCharacteristics = "";
        boolean isUploadFineCode = false;
        for (GpProductUpdate gpProductUpdate : orderAdd.getProductList()) {
            gpProduct = Convert.convert(new TypeReference<GpProduct>() {}, gpProductUpdate);
            gpProduct.setOrderId(orderId);
            gpProductService.save(gpProduct);


            // 保存订单产品详情信息
            productId = gpProduct.getId();
            for (GpProductDetailsUpdate gpProductDetailsUpdate : gpProductUpdate.getDetails()) {
                gpProductDetailsUpdate.setId(null);
                gpProductDetails = Convert.convert(new TypeReference<GpProductDetails>() {}, gpProductDetailsUpdate);
                gpProductDetails.setOrderId(orderId);
                gpProductDetails.setProductId(productId);
                gpProductDetailsService.save(gpProductDetails);
                // 计算是大货还是散剪，计算工作量
                if (StringUtils.equals(gpProductDetailsUpdate.getProductUnitTagName(), "公斤")
                        ||(StringUtils.equalsIgnoreCase(gpProductDetailsUpdate.getProductUnitTagName(),"kg") && gpProductDetails.getQuantityTag().compareTo(BigDecimal.valueOf(2)) > 0)
                        || StringUtils.equals(gpProductDetailsUpdate.getProductUnitTagName(), "条")
                        || gpProductDetails.getQuantityTag().compareTo(BigDecimal.valueOf(19)) > 0)   {
                    orderCharacteristics = OrderCharacteristicsEnum.BIG.getKey();
                    if (StringUtils.equals(gpProductDetailsUpdate.getProductUnitTagName(), "公斤") || StringUtils.equals(gpProductDetailsUpdate.getProductUnitTagName(), "条")) {
                        workload = workload.add(BigDecimal.valueOf(1)).add(gpProductDetails.getQuantityTag().divide(BigDecimal.valueOf(20), 0, RoundingMode.CEILING).multiply(BigDecimal.valueOf(0.3)));
                    } else {
                        workload = workload.add(BigDecimal.valueOf(1)).add(gpProductDetails.getQuantityTag().divide(BigDecimal.valueOf(100), 0, RoundingMode.CEILING).multiply(BigDecimal.valueOf(0.3)));
                    }
                } else {
                    workload = workload.add(BigDecimal.valueOf(1.5));
                    if (!StringUtils.equals(orderCharacteristics, OrderCharacteristicsEnum.BIG.getKey())) {
                        orderCharacteristics = OrderCharacteristicsEnum.LOOSE_SHEAR.getKey();
                    }
                }
                // 判断订单是否需要上传细码
                if (!isUploadFineCode) {
                    // 只要有一条规格满足上传细码条件就不需要再进行判断
                    isUploadFineCode = this.isUploadFineCode(gpProductUpdate.getProductName(), gpProductDetailsUpdate);
                }

                if (StringUtils.isEmpty(gpProductUpdate.getProductName())){
                    workload=new BigDecimal("1");
                }


            }
        }
        //如果订单类型为销售结算单（原采购退货单）则统一设置为大货
        gpOrder.setOrderCharacteristics(StringUtils.equals(orderAdd.getFormType().toString(), FormTypeEnum.PURCHASE_RETURN.getKey()) ? OrderCharacteristicsEnum.BIG.getKey() :  orderCharacteristics);
        gpOrder.setWorkload(workload);
        // 生成二维码
        String date = DateUtils.datePath();
        String uuid = IdUtils.fastUuid();
        String filePath = GpframeworkConfig.getUploadPath() + "/" + date + "/" + uuid + ".jpg";
        File file = FileUtil.file(filePath);
        if (!file.exists()) {
            // 文件不存在，创建新文件
            FileUtil.touch(file);
        }
        QrCodeUtil.generate(gpOrder.getOrderCloudNumber() + "?50-" + gpOrder.getOrderCloudNumber(), 300, 300, file);
        gpOrder.setOrderQrCode(Constants.RESOURCE_PREFIX + "/upload/" + date + "/" + uuid + ".jpg");
        gpOrder.setCreateBy(orderAdd.getCreateBy());
        this.updateById(gpOrder);
        orderAdd.setOrderQrCode(gpOrder.getOrderQrCode());
        orderAdd.setFormCode(gpOrder.getFormCode());
        GpOrderVo gpOrderVo = Convert.convert(new TypeReference<GpOrderVo>() {}, orderAdd);
        // 发送消息通知
        GpFlowConfig flowConfig = gpFlowConfigService.getOne(new QueryWrapper<GpFlowConfig>().eq("del_status", YesNoEnum.NO.getKey()).orderByAsc("sort").last("limit 1"));
        if (flowConfig != null) {
            gpOrderNotifyService.sendNotifyByConfigId(flowConfig.getId(), gpOrder.getId());
        }
        return AjaxResult.success(gpOrderVo);
    }

    /**
     * 判断订单是否需要上传细码
     * @param productName
     * @param gpProductDetailsUpdate
     * @return
     */
    private boolean isUploadFineCode(String productName, GpProductDetailsUpdate gpProductDetailsUpdate){
        boolean isUploadFineCode = false;
        if (gpProductDetailsUpdate.getQuantityTag() == null || !StringUtils.equals("码", gpProductDetailsUpdate.getProductUnitTagName())) {
            // 如果没有数量或单位不为‘码’，则无需上传细码
            return isUploadFineCode;
        }
        List<String> productNameList = Arrays.asList("巴黎网", "45A", "40A");
        if (productNameList.contains(productName)) {
            // 如果产品名为指定的三个产品，判断产品码数
            if (gpProductDetailsUpdate.getQuantityTag().compareTo(BigDecimal.valueOf(130)) != 0
                    && gpProductDetailsUpdate.getQuantityTag().compareTo(BigDecimal.valueOf(140)) != 0) {
                // 码数不为130和140，需要上传细码
                isUploadFineCode = true;
            }
        } else if (gpProductDetailsUpdate.getQuantityTag().compareTo(BigDecimal.valueOf(100)) > 0) {
            // 如果产品名不为指定的三个产品，且数量>100，则需要上传细码
            isUploadFineCode = true;
        }
        return isUploadFineCode;
    }

    @Override
    public GpHomeStatisticsVo homeStatistics(QueryWrapper<GpOrder> lqw) {
        return this.baseMapper.homeStatistics(lqw);
    }

    @Override
    public GpHomeStatisticsVo todayHomeStatistics(QueryWrapper<GpOrder> lqw) {
        return this.baseMapper.todayHomeStatistics(lqw);
    }

    @Override
    public List<GpOrderVo> overdueOrderList(GpOrderReq gpOrderReq) {
        return this.baseMapper.overdueOrderList(gpOrderReq);
    }

    @Override
    public List<GpOrderVo> largeScreenList(String orderStatus) {
        return this.baseMapper.largeScreenList(orderStatus);
    }

    @Override
    public int getCount(QueryWrapper<GpOrder> queryWrapper) {
        return this.baseMapper.getCount(queryWrapper);
    }


    @Override
    public int getCountHistory(QueryWrapper<GpOrder> queryWrapper) {
        return this.baseMapper.getCountHistory(queryWrapper);
    }
    @Override
    @Transactional
    public boolean outOfStock(GpOrderUpdateMy gpOrderUpdate) {
        GpOrder gpOrder = Convert.convert(new TypeReference<GpOrder>() {}, gpOrderUpdate);
        // 更新原订单数量
        List<GpProduct> productList = Convert.convert(new TypeReference<List<GpProduct>>() {}, gpOrderUpdate.getProductList());
        gpProductService.updateBatchById(productList);
        for (GpProductUpdateMy gpProductUpdate : gpOrderUpdate.getProductList()) {
            List<GpProductDetails> details = Convert.convert(new TypeReference<List<GpProductDetails>>() {}, gpProductUpdate.getDetails());
            gpProductDetailsService.updateBatchById(details);
        }
        // 生成子订单
        GpOrderAdd gpOrderAdd = new GpOrderAdd();
        BeanUtils.copyProperties(gpOrder, gpOrderAdd);
        gpOrderAdd.setParentId(gpOrder.getId());
        gpOrderAdd.setIsException(1);
        gpOrderAdd.setExceptionType("欠货");
        gpOrderAdd.setOrderCloudNumber(null);
        // 如果订单状态从正常改成异常，记录暂停开始时间
        gpOrderAdd.setSuspendStartTime(new Date());
        gpOrderAdd.setFormCode(gpOrder.getFormCode() + "-1");
        List<GpProductUpdate> outOfStockProductList = new ArrayList<>();
        GpProductUpdate gpProductUpdate;
        List<GpProductDetailsUpdate> outOfStockProductDetailsList;
        for (GpProductUpdateMy gpProductUpdateMy : gpOrderUpdate.getOutOfStockProductList()) {
            gpProductUpdate = Convert.convert(new TypeReference<GpProductUpdate>() {}, gpProductUpdateMy);
            outOfStockProductDetailsList = Convert.convert(new TypeReference<List<GpProductDetailsUpdate>>() {}, gpProductUpdateMy.getDetails());
            gpProductUpdate.setDetails(outOfStockProductDetailsList);
            outOfStockProductList.add(gpProductUpdate);
        }
        gpOrderAdd.setProductList(outOfStockProductList);
        this.collection(gpOrderAdd);
        return this.updateById(gpOrder);
    }

    /*public JSONObject noticeTemplate(JSONObject templateMsg) {
        // 模版ID
        String templateId = "EdIYIjFaaoSx1dCav5pQYUxaQlC0hXUeKYAD5IbZ7jY";
        TreeMap<String, TreeMap<String, String>> params = new TreeMap<>();

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        //微信公众号根据具体模板参数组装
        params.put("time5", WxSendMessageTemplate.item(sdf.format(new Date()), "#000000")); //派工时间
        params.put("const6", WxSendMessageTemplate.item(templateMsg.getString("今日报表已生成"), "#000000"));    //派工内容
        WxSendMessageTemplate wxTemplateMsg = new WxSendMessageTemplate();
        // 模版ID
        wxTemplateMsg.setTemplate_id(templateId);
        // openId
        wxTemplateMsg.setTouser(templateMsg.getString("openId"));
        // 关键字赋值
        wxTemplateMsg.setData(params);

        String data = JsonUtils.ObjectToString(wxTemplateMsg);
        System.out.println(data);
        return this.handleSendMsgLog(data);
    }

    //捕获异常
    private JSONObject handleSendMsgLog(String data) {
        JSONObject resultDto = new JSONObject();
        try {
            resultDto = this.sendTemplateMsg(data);
            System.out.println("handleSendMsgLog:" + resultDto.toJSONString());
        } catch (Exception exception) {
            log.error("发送微信模版失败",  exception);
        }
        // TODO 可以记录一下发送记录的日志
        return resultDto;
    }

    //发送模板
    public JSONObject sendTemplateMsg(String data) throws Exception {
        // 获取token
        JSONObject accessTokenRes = this.getAccessToken();
        String accessToken = accessTokenRes.getString("access_token");
        // 发送消息
        HttpResult httpResult = null;
        try {
            httpResult = httpUtils.stringPostJson(WxConfiguration.getSendMessageTemplateUrl() + accessToken, data);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return JSON.parseObject(httpResult.getBody());
    }


    // 获取全局access_token
    public JSONObject getAccessToken() {
        //拼接获取缓存key
        String key = ACCESS_TOKEN_KEY_PREFIX.concat(WxConfiguration.getAppId()).concat(WxConfiguration.getSecret());
        Map<String, Object> accessTokenJson = accessTokenMap.get(key);

        if (accessTokenJson != null) {
            long expiresIn = (Long) accessTokenJson.get(KEY_EXPIRES_IN);
            if (System.currentTimeMillis() < expiresIn) {
                return (JSONObject) accessTokenJson.get(KEY_TOKEN);
            }
            accessTokenMap.remove(key);
        }

        synchronized (this) {
            accessTokenJson = accessTokenMap.get(key);
            // 多线程环境下，其他线程可能已经获得最新corpAccessToken，直接返回
            if (accessTokenJson != null) {
                return (JSONObject) accessTokenJson.get(KEY_TOKEN);
            }

            String url = String.format(WxConfiguration.getWxAccessTokenUrl(), WxConfiguration.getAppId(), WxConfiguration.getSecret());
            JSONObject resJson = httpUtils.stringGetJson(url);

            if (resJson != null && StringUtils.isNotEmpty(resJson.getString("access_token"))) {
                accessTokenJson = this.seAccessToken(resJson);
            }

            if (accessTokenJson == null) {
                try {
                    throw new Exception();
                } catch (Exception e) {
                    log.error("设置access_token缓存失败");
                    e.printStackTrace();
                }
            }
            //放入缓存中
            accessTokenMap.put(key, accessTokenJson);
            JSONObject accessTokenJsonRes = (JSONObject) accessTokenJson.get(KEY_TOKEN);
            if (accessTokenJsonRes == null) {
                try {
                    throw new Exception();
                } catch (Exception e) {
                    log.error("获取access_token错误");
                    e.printStackTrace();
                }
            }
            return accessTokenJsonRes;
        }
    }

    //设置access_token
    private Map<String, Object> seAccessToken(JSONObject jsonObject) {
        Map<String, Object> token = Maps.newHashMap();
        // 减去3分钟，以免过时
        token.put(KEY_EXPIRES_IN, (jsonObject.getLongValue("expires_in") - 3 * 60) * 1000 + System.currentTimeMillis());
        token.put(KEY_TOKEN, jsonObject);
        return token;
    }*/

}
